﻿''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' NOTICE                                                                             '
' -------                                                                            '
' Portions of this source code were taken from the Windows 7 Taskbar Single Instance '
' recipe, which can be found at the following URL:                                   '
' http://code.msdn.microsoft.com/Windows-7-Taskbar-Single-4120eafd                   '
'                                                                                    '
' The Windows 7 Taskbar Single Instance recipe is released under the Apache License, '
' version 2.0. This license is located at the following URL:                         '
' http://www.apache.org/licenses/LICENSE-2.0                                         '
'                                                                                    '
' This program also uses James Newton-King's Json.NET library, which can be found at '
' http://json.codeplex.com/                                                          '
'                                                                                    '
' Json.NET is licensed under the MIT license, which as of 4/11/2011, can be found at '
' http://json.codeplex.com/license                                                   '
'                                                                                    '
' This source code itself is licensed under the MIT license, which can be found at   '
' http://collegiate.codeplex.com/license                                             '
'                                                                                    '
' All mentioned licenses can be found in the Licenses folder provided with this code.'
'                                                                                    '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Imports System.Threading
Imports System
Imports System.Windows
Imports System.Windows.Interop
Imports WindowsRecipes.TaskbarSingleInstance
Imports WindowsRecipes.TaskbarSingleInstance.Wpf
Imports Microsoft.WindowsAPICodePack.Shell
Imports Microsoft.WindowsAPICodePack.Taskbar
Imports System.IO
Imports Newtonsoft.Json

''' <summary>
''' This class handles most of the actual logic
''' </summary>
''' <remarks></remarks>
Class MainWindow
    ' Convoluted (but safe?) method of getting the preferred data save path
    ' "~/AppData/Roaming/Collegiate/saveddata.collegiate"
    Private SAVEDATAPATH As String = _
        My.Computer.FileSystem.CombinePath( _
        My.Computer.FileSystem.CombinePath( _
        Environment.GetFolderPath( _
            Environment.SpecialFolder.ApplicationData), _
            "Collegiate"), _
            "saveddata.collegiate")

    Private HELPFILEPATH As String = _
        My.Computer.FileSystem.CombinePath( _
        My.Computer.FileSystem.CombinePath( _
        Environment.GetFolderPath( _
            Environment.SpecialFolder.ApplicationData), _
            "Collegiate"), _
            "helpfile.chm")

    ' List to hold all data
    Private myData As New List(Of Professor)
    ' List to point to all the courses in myData
    Private courses As New List(Of Course)
    ' Control that keeps track of Courses
    Private courseList As New Controls.CollegiateCourseList()
    ' List to point to all the assignments in myData
    Private assignments As New List(Of Assignment)
    ' Control that keeps track of Assignments
    Private assignmentList As New Controls.CollegiateAssignmentList()

    ' Create a variable to easily access current app instance
    Private CurrentApp As Collegiate.App = DirectCast(Application.Current, Collegiate.App)

    ''' <summary>
    ''' This runs when the main window loads
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub OnWindowLoaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
        ' Yeah, so... Hi.
        ' What would I say I've learned from this project?
        ' I'd say I learned that in the future, opt for a global module,
        ' rather than pass the same information around to several places.

        ' Setup the Jumplist
        CurrentApp.CreateJumpList()

        ' Add the AssignmentList Control, since the UI builder code hates me
        Body.Children.Add(assignmentList)

        ' Synchronize the courseList with the window's stackpanel and menu for options
        courseList.Sync(menuClasses, OptionsCoursesStack)

        ' Make sure the Assignment class has a synchonized list of courses and assignments
        Assignment.courseList = courses
        Assignment.assignmentList = assignments
        ' As well as access to the Edit and Delete Assignment lists of assignments
        Assignment.assignmentEditMenu = Body.FindName("AssignmentEditMenu")
        Assignment.assignmentDeleteMenu = Body.FindName("AssignmentDeleteMenu")

        ' And that the Course class has a synchronized list of courses
        Course.courseList = courses
        ' As well as Edit and Delete Course lists
        Course.courseEditMenu = Body.FindName("CourseEditMenu")
        Course.courseDeleteMenu = Body.FindName("CourseDeleteMenu")

        ' Give Professor access to the edit/delete menus
        Professor.professorEditMenu = Body.FindName("ProfessorEditMenu")
        Professor.professorDeleteMenu = Body.FindName("ProfessorDeleteMenu")

        ' Don't ask... At this point, I'm throwing good practice out the window,
        ' just to get the project done in time for finals.
        courseList.assignmentList = assignmentList

        ' ...
        courseList.courseList = courses
        assignmentList.assignments = assignments

        ' Load initial Data
        ' Includes "InitialBuildForm" Subroutine call
        initialLoadData(SAVEDATAPATH)

        ' Course and Professor need a synchronized list of professors, created after Data is loaded
        Course.professorList = myData
        Professor.professorList = myData

        ' Clip the thumbnail
        ' If TaskbarManager.IsPlatformSupported Then setThumbnailClip()

        ' Grab the initial instance's command line arguments
        CurrentApp.ProcessCommandLineArgs(Environment.GetCommandLineArgs)

    End Sub

    ''' <summary>
    ''' Function to set the Windows 7 taskbar's thumbnail clip to a small section of the program
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub setThumbnailClip()

        ' Redraw the Window Thumbnail to only show the list of assignments
        TaskbarManager.Instance.TabbedThumbnail.SetThumbnailClip( _
            New WindowInteropHelper(Me).Handle, _
            New System.Drawing.Rectangle(OptionsScrollViewer.ActualWidth, _
                                         0, _
                                         AssignmentList.ActualWidth, _
                                         AssignmentList.ActualHeight))
    End Sub

    ''' <summary>
    ''' Runs once at program start, loads the saved data and deserializes it
    ''' </summary>
    ''' <param name="filePath"></param>
    ''' <remarks></remarks>
    Private Sub initialLoadData(ByVal filePath As String)
        If My.Computer.FileSystem.FileExists(filePath) Then
            Try
                Dim fileStream As New StreamReader(filePath)
                Dim fileString As String = fileStream.ReadToEnd()
                myData = JsonConvert.DeserializeObject(Of List(Of Professor))(fileString)
                fileStream.Close()
            Catch
                ' Something went wrong!
                ' I'm just a student, someone else can handle the whole error-log and reporting stuff
                backupFile(filePath, "corrupted")
                myData = newData()
                saveData(SAVEDATAPATH)
            Finally
                buildForm()
            End Try
        Else
            myData = newData()
            saveData(SAVEDATAPATH)
            buildForm()
        End If
    End Sub

    ''' <summary>
    ''' Serializes the data and saves it in JSON format
    ''' </summary>
    ''' <param name="filePath"></param>
    ''' <remarks></remarks>
    Private Sub saveData(ByVal filePath As String)
        Try
            Dim fileStream As New StreamWriter(filePath)
            fileStream.Write(JsonConvert.SerializeObject(myData, Formatting.Indented))
            fileStream.Close()
        Catch exc As Exception
            MessageBox.Show("Couldn't save data:" & vbNewLine & exc.Message)
        End Try
    End Sub

    ''' <summary>
    ''' Method that saves a backup of the data (serialize + save in JSON) in the user specified spot
    ''' </summary>
    ''' <param name="filePath"></param>
    ''' <param name="tag"></param>
    ''' <remarks></remarks>
    Private Sub backupFile(ByVal filePath As String, ByVal tag As String)
        ' Copies file as "collegiate.[tag].[date].backup"
        My.Computer.FileSystem.CopyFile( _
            filePath, _
            My.Computer.FileSystem.CombinePath( _
                My.Computer.FileSystem.GetParentPath(filePath), _
                String.Concat("collegiate.", tag, ".", Now.Ticks.ToString(), ".backup")))
    End Sub

    ''' <summary>
    ''' One-run method that builds the forms professors/courses/assignments after initializing data
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub buildForm()
        ' For each professor...
        For Each prof As Professor In myData
            ' Add it to the menus
            prof.addToMenus()

            ' For each course in each professor...
            For Each subj As Course In prof.courses

                subj.parent = prof

                ' Add the course to the list
                courseList.Add(subj)

                ' And for each assignment in each course...
                For Each asgn As Assignment In subj.assignments

                    ' Set assignment's parent to proper course
                    asgn.parent = subj

                    ' Add to list
                    assignmentList.Add(asgn)
                Next
            Next
        Next
    End Sub

    ''' <summary>
    ''' Creates a new data save file (if no old data exists, or its corrupt)
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function newData() As List(Of Professor)
        Dim profs As New List(Of Professor)

        Dim prof As New Professor() With { _
            .name = "Default Professor",
            .notes = "Default Professor",
            .website = "http://collegiate.codeplex.com"}

        Dim subj As New Course() With { _
            .name = "Default Course",
            .notes = "Default Course",
            .color = Colors.LightBlue}

        Dim asgn As New Assignment() With { _
            .name = "Default Assignment",
            .notes = "Default Assignment",
            .endDate = Today.AddDays(2),
            .priority = AssignmentPriority.high}

        subj.assignments.Add(asgn)
        prof.courses.Add(subj)
        profs.Add(prof)

        Return profs
    End Function

    ''' <summary>
    ''' Function that receives command line arguments, then delegates tasks based on input
    ''' </summary>
    ''' <param name="args"></param>
    ''' <remarks></remarks>
    Public Sub handleCommandLineArgs(ByVal args As String())
        Me.Activate()

        Try
            If args.Length >= 2 Then
                Select Case args(1)
                    Case "NewAssignment"
                        newAssignment()
                    Case "Testing"
                        MessageBox.Show("Hi")
                        Exit Select
                    Case "Test2"
                        MessageBox.Show("Hello")
                        Exit Select
                    Case Else
                        Debug.Assert(False, "Should not be here")
                        Exit Select
                End Select
            End If
        Catch generatedExceptionName As ArgumentException
            Debug.Assert(False, [String].Format("Wrong command line parameter: {0}", args(1)))
        End Try
    End Sub

    ''' <summary>
    ''' Creates a new assignment
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub newAssignment()
        ' Create new assignment
        Dim assign As New Assignment()

        AddHandler assign.created, AddressOf assignmentCreated
        assign.Create()
        RemoveHandler assign.created, AddressOf assignmentCreated
    End Sub

    ''' <summary>
    ''' Creates a new course
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub newCourse()
        ' Create new course
        Dim subj As New Course()

        AddHandler subj.created, AddressOf courseCreated
        subj.Create()
        RemoveHandler subj.created, AddressOf courseCreated
    End Sub

    ''' <summary>
    ''' Creates a new professor
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub newProfessor()
        ' Create new professor
        Dim prof As New Professor()

        prof.Create()
    End Sub

    ''' <summary>
    ''' Calls the "Save Data" method when the "Save" menu item is clicked
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub save_click()
        saveData(SAVEDATAPATH)
    End Sub

    ''' <summary>
    ''' Adds an assignment to the assignment list when the assignment throws what is essentially "Yes, the user went through with creating me instead of cancelling halfway through."
    ''' </summary>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Public Sub assignmentCreated(ByRef e As Assignment)
        assignmentList.Add(e)
    End Sub

    ''' <summary>
    ''' Adds a course to the course list when the course throws what is essentially "Yes, the user went through with creating me instead of cancelling halfway through."
    ''' </summary>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Public Sub courseCreated(ByRef e As Course)
        courseList.Add(e)
    End Sub

    ''' <summary>
    ''' Tells the assignmentlist that the user just changed what assignments they want to view (all, overdue, due today, etc)
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Public Sub assignmentVisibilityChanged(ByVal sender As RadioButton, ByVal e As System.EventArgs)
        Select Case sender.Name
            Case "rdoAllAssignments"
                assignmentList.assignmentVisibility = 0
            Case "rdoOverdueAssignments"
                assignmentList.assignmentVisibility = 1
            Case "rdoDueToday"
                assignmentList.assignmentVisibility = 2
            Case "rdoDueTomorrow"
                assignmentList.assignmentVisibility = 3
            Case "rdoUpcoming"
                assignmentList.assignmentVisibility = 4
        End Select
    End Sub

    ''' <summary>
    ''' Tells the assignmentlist that the user just changed what assignments they want to view (all courses, only course 1, only course 2, etc)
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Public Sub courseVisibilityChanged(ByVal sender As RadioButton, ByVal e As System.EventArgs)
        assignmentList.courseVisibility = "All Courses"
        assignmentList.hideAssignments()
    End Sub

    ''' <summary>
    ''' Opens the included help file when the user clicks the "View Help" menuitem
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub openHelp()
        If File.Exists(HELPFILEPATH) Then
            System.Diagnostics.Process.Start(HELPFILEPATH)
        Else
            MessageBox.Show("Sorry!" & vbNewLine & "The Help File could not be found!", "Help")
        End If
    End Sub

    ''' <summary>
    ''' Opens the Collegiate project page at Codeplex when the user clicks the "View Project Page" menuitem
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub openProjectPage()
        System.Diagnostics.Process.Start("http://collegiate.codeplex.com")
    End Sub
End Class
